#include "FeedConnectorImpl.h"

#include <boost/bind.hpp>

namespace AlgoTrading
{
	namespace ConnectionLibrary
	{

		FeedConnectorImpl::FeedConnectorImpl(boost::asio::io_service& io_service, std::tr1::weak_ptr<NotificationHandler> notificationHandler)
			: notificationHandler(notificationHandler)
			, socketReaderWriter((SocketReaderWriter*)0)
			, io_service(io_service)
			, socket(0)
		{
		}

		FeedConnectorImpl::~FeedConnectorImpl()
		{
			Disconnect();
		}

		boost::system::error_code FeedConnectorImpl::Connect(const std::string& host, const std::string& serviceNameOrPort)
		{
			tcp::resolver resolver(io_service);
			tcp::resolver::query query(host, serviceNameOrPort);
			tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
			tcp::resolver::iterator end;

			socket = std::auto_ptr<tcp::socket>(new tcp::socket(io_service));
			boost::system::error_code error = boost::asio::error::host_not_found;
			while (error && endpoint_iterator != end)
			{
				socket->close();
				socket->connect(*endpoint_iterator++, error);
			}

			if (!error)
			{
				socket->set_option(tcp::no_delay(true));
				socketReaderWriter = std::auto_ptr<SocketReaderWriter>(new SocketReaderWriter(io_service, *socket, static_cast<SocketNotificationHandler&>(*this)));
				socketReaderWriter->StartReading();
			}
			return error;
		}

		void FeedConnectorImpl::Disconnect()
		{
			if (socketReaderWriter.get())
			{
				socketReaderWriter->Disconnect();
				socketReaderWriter.reset();
			}
		}

		void FeedConnectorImpl::SendRequest(const AlgoTrading::Messages::RequestWithoutResponse& request)
		{
			OutputMessageBufferHolderPtr outputMessageBufferHolder(new OutputMessageBufferHolder());
			//TODO: refactor this
			request.Serialize(outputMessageBufferHolder->GetOutputStream());
			outputMessageBufferHolder->ParseMessageLength();
			
			if (socketReaderWriter.get())
			{
				socketReaderWriter->SendBuffer(outputMessageBufferHolder);
			}
		}

		void FeedConnectorImpl::SendRequest(const AlgoTrading::Messages::RequestWithResponse& request)
		{
			OutputMessageBufferHolderPtr outputMessageBufferHolder(new OutputMessageBufferHolder());
			request.Serialize(outputMessageBufferHolder->GetOutputStream());
			outputMessageBufferHolder->ParseMessageLength();

			if (socketReaderWriter.get())
			{
				socketReaderWriter->SendBuffer(outputMessageBufferHolder);
			}
		}

		void FeedConnectorImpl::OnError(const boost::system::error_code& error)
		{
			std::tr1::shared_ptr<NotificationHandler> noficationHandler = this->notificationHandler.lock();
			if (noficationHandler)
			{
				noficationHandler->OnError(error);
			}
		}

		void FeedConnectorImpl::OnDisconnect()
		{
			std::tr1::shared_ptr<NotificationHandler> noficationHandler = this->notificationHandler.lock();
			if (noficationHandler)
			{
				noficationHandler->OnDisconnect();
			}
		}

		void FeedConnectorImpl::ParseMessageData(std::istream& stream)
		{
			std::auto_ptr<AlgoTrading::Messages::ServerMessage> serverMessage = AlgoTrading::Messages::ServerMessage::Deserialize(stream);
			AlgoTrading::Messages::ServerMessage::ServerMessageType serverMessageType = serverMessage->GetServerMessageType();
			if (serverMessageType == AlgoTrading::Messages::ServerMessage::REQUEST_RESPONSE)
			{
				std::tr1::shared_ptr<NotificationHandler> noficationHandler = this->notificationHandler.lock();
				if (noficationHandler)
				{

					noficationHandler->OnRequestResponse(*(static_cast<AlgoTrading::Messages::RequestResponse*>(serverMessage.get())));
				}
			}
			else if (serverMessageType == AlgoTrading::Messages::ServerMessage::NOTIFICATION_MESSAGE)
			{
				std::tr1::shared_ptr<NotificationHandler> noficationHandler = this->notificationHandler.lock();
				if (noficationHandler)
				{
					noficationHandler->OnNotification(*(static_cast<AlgoTrading::Messages::NotificationMessage*>(serverMessage.get())));
				}
			}
		}

	}
}

